#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/irqreturn.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/input.h>


struct key_gpio *key_gpios;
int gpio_cnt;
static struct input_dev *key_input;

static int KEY[10] = {KEY_ENTER, KEY_L, KEY_S};  //38  31  28

struct key_gpio{
	int gpio;
	int irq;
	int key;
	int value;
	struct timer_list my_timer;
};

static void my_timer_handle(unsigned long data)
{
	struct key_gpio *key_gpio_irq = (struct key_gpio *)data;

//	printk("key is: %d, gpio is: %d\n", key_gpio_irq->key, key_gpio_irq->gpio);

	/* 5.input子系统上报事件 */
	key_gpio_irq->value = gpio_get_value(key_gpio_irq->gpio);

	//第三个参数要变，如果两次上报value相同，则input子系统不会响应
	input_report_key(key_input, key_gpio_irq->key, key_gpio_irq->value);  

	/* 6.同步事件 */
	input_sync(key_input);
}

static irqreturn_t key_irq_handler(int irq, void *dev_id)
{
	struct key_gpio * kg = (struct key_gpio *)dev_id;
	mod_timer(&kg->my_timer , jiffies+HZ/50);
	return IRQ_HANDLED;
}

static int key_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	int i, err;

	gpio_cnt = of_gpio_count(node);

	key_gpios = kzalloc(sizeof(struct key_gpio) * gpio_cnt, GFP_KERNEL);

	for(i = 0; i < gpio_cnt; i++){
		key_gpios[i].value = 0;
		key_gpios[i].key = KEY[i];
		key_gpios[i].gpio = of_get_gpio(node, i);
		key_gpios[i].irq = gpio_to_irq(key_gpios[i].gpio);
		err = request_irq(key_gpios[i].irq, key_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq", &key_gpios[i]);

		key_gpios[i].my_timer.expires = 0;
		setup_timer(&key_gpios[i].my_timer, my_timer_handle, (unsigned long)&key_gpios[i]);
		add_timer(&key_gpios[i].my_timer);
	}
	
	return 0;
}

static int key_remove(struct platform_device *dev)
{
	int i;

	for(i = 0; i < gpio_cnt; i++){
		free_irq(key_gpios[i].irq, &key_gpios[i]);
		del_timer(&key_gpios[i].my_timer);
	}
	return 0;
}


static const struct of_device_id key_of_match[] = {
	{ .compatible = "hc-key" },
};


static struct platform_driver key_plt_dev = {
	.probe		= key_probe,
	.remove		= key_remove,
	.driver		= {
		.name	= "my_key",
		.of_match_table	= key_of_match,	
	},
};


static int key_drv_init(void)
{
	int err;

	err = platform_driver_register(&key_plt_dev);

	/* 1.申请空间 */
	key_input = input_allocate_device();
	if(key_input == NULL){
		printk("input alloc failed\n");
		return -ENOMEM;
	}
	/* 2.设置事件类型 */
	set_bit(EV_KEY, key_input->evbit);
	set_bit(EV_SYN, key_input->evbit);

	/* 3.设置子事件：具体按键 */
	set_bit(KEY_L,key_input->keybit);
	set_bit(KEY_S,key_input->keybit);
	set_bit(KEY_ENTER,key_input->keybit);
					
	/* 4.注册input子系统 */
	err = input_register_device(key_input);
	if(err){
		printk("input register failed\n");
		return -EAGAIN;
	}
	
	printk("This is key_drv_init\n");
	return 0;
}

static void key_drv_exit(void)
{
	printk("This is key_drv_exit\n");
	platform_driver_unregister(&key_plt_dev);
	input_unregister_device(key_input);
	input_free_device(key_input);
}


module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");



//static int major;
//static struct class * key_class;
//
//static int key_open (struct inode *node, struct file *filp)
//{
//
//}
//
//static ssize_t key_read (struct file *filp, char __user *buf, size_t, loff_t *offset)
//{
//	return 0;
//}
//
//static int key_release (struct inode *node, struct file *filp)
//{
//	return 0;
//}
//
//static struct file_operations key_ops = {
//	.owner = THIS_MODULE,
//	.open = key_open,
//	.read = key_read,
//	.release = key_release,
//};
//
//static int key_drv_init(void)
//{
//	int err;
//	printk("This is key_drv_init\n");
//	major = register_chrdev(0, "key_drv", &key_ops);
//	key_class = class_create(THIS_MODULE, "key_class");
//	err = device_create(key_class, NULL, MKDEV(major, 0), NULL, "key");
//	if (err)
//		return -ENODEV;
//	printk("create device /dev/key success\n");
//	
//	return 0;
//}
//
//static void key_drv_exit(void)
//{
//	printk("This is key_drv_exit\n");
//}
//
//module_init(key_drv_init);
//module_exit(key_drv_exit);
//MODULE_LICENSE("GPL");



